home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / Libraries / VideoToolbox 96.06.15 / VideoToolboxSources / Assign.doc < prev    next >
Text File  |  1995-09-26  |  31KB  |  595 lines

  1. #if 0
  2. Assign.doc
  3. This file documents Assign.c.
  4.  
  5. Assign is a portable runtime C interpreter that reads and executes any text
  6. "assignment" file that contains only C assignments and comments, e.g.
  7.     viewingDistance=57.0;    /* inches */
  8. It uses an array of "Description" structures to associate each name in the
  9. assignment file with a corresponding runtime C variable. It can also write an
  10. assignment file, making the assignment file a portable way of writing and
  11. reading calibrations and experimental parameters. Arrays can be allocated
  12. dynamically, automatically dimensioned so as to hold all the assignments in any
  13. part of the assignment file.
  14.  
  15. Programs written before 1993, using the old ReadAssignments.c (now superceded by 
  16. Assign.c), may #include the header file Assign92.h to minimize the effort of 
  17. updating.
  18.  
  19. PORTABILITY: Standard C
  20.  
  21. SYNTAX OF THE ASSIGNMENT FILE
  22.  
  23. The entire "assignment" file may contain only simple assignments--which are
  24. interpreted--and whitespace and comments--which are ignored. Both C style /* */
  25. and C++ style // comments are allowed. Ignoring any intervening whitespace and
  26. comments, each assignment consists of a variable name of any length, possibly
  27. with a constant subscript (of up to ASSIGN_DIMS dimensions), an equal sign,
  28. either a constant (decimal 13, 1.3, 1.3e9, hex 0x1a, char 'a', transcendental
  29. Inf, or not-a-number NaN) or a string literal (e.g. "hello"), and a semicolon.
  30.     i=3; a=1.0; b[1][2]=INF; msg="hello world"; /* examples */
  31. NaN (or NAN or nan), Inf (or INF or inf), and -Inf are accepted as floating
  32. values. (The NAN specification may include a NAN-code, a la THINK C, e.g. NANFF,
  33. or ala MPW C, e.g. NAN[255].) Backslash escapes, e.g. \007 and \n, within single
  34. or double quotes are fully supported (except that there is no support for Standard C's
  35. new international "wide" characters and trigraph sequences). A simple variable
  36. name, as in C, consists of an alphabetic character (or _) followed by any number
  37. of alphanumeric characters (or _). To simulate structure references, composite
  38. names are allowed, made up of simple names joined by "." or "->", e.g.
  39.     a->b.c=0.0; myStruct->b=INF;
  40. Unlike Standard C, each line must be less than BUFFER_SIZE characters long (currently
  41. 512). Lines that end with the backslash character \ are spliced to the next by
  42. deleting the backslash and the following newline character. The splice may be
  43. between tokens or inside a comment or string literal, but, unlike C, the splice
  44. may not break a token. Adjacent string literals "a" "b" are concatenated "ab",
  45. as specified by Standard C. (The line splicing and adjacent concatenation allow
  46. creation of strings of arbitrary length, not limited by BUFFER_SIZE.) No further
  47. expression evaluation is supported. No other operators, e.g. +-&*, enums, casts,
  48. e.g. (unsigned long), or number suffixes, e.g. UL, are allowed. No macros or
  49. preprocessor directives are supported (e.g. #if, #define). The syntax rules are
  50. strictly enforced. If ReadAssignmentLine can't interpret your file it will, at
  51. the caller's option, either return an error code or call PrintfExit with an
  52. error message pinpointing the error.
  53.  
  54. Assign.c supports one optional extension beyond C syntax that makes it practical
  55. to save images within assignment files. If a non-string variable is assigned a
  56. string, 
  57.     a="1111aaaa1111";
  58. then ReadAssignmentLine assumes that the string is an encoding of the desired
  59. binary object as a hexadecimal number, and assigns the decoded binary object to
  60. the variable, one byte for every two hex digits. This is supported for both
  61. scalar and array variables--treating either an element or a row (last subscript,
  62. fastest changing) of the array as a single binary object--so you can load or
  63. save a huge row by a single statement that assigns a humungous string of hex
  64. data to the array. E.g. if m[][] is of type char, then the following three lines
  65. are equivalent.
  66.     m[3][0]=155;m[3][1]=95;m[3][2]=255;m[3][3]=127;
  67.     m[3][0]="9b";m[3][1]="5f";m[3][2]="ff";m[3][3]="7f";
  68.     m[3]="9b5fff7f";
  69. This format is supported by both ReadAssignmentLine and PrintAnAssignment. When
  70. reading an assignment file, a binary object containing only one element, as in
  71. m[3][0]="9b", is interpreted as a scalar, rather than as a row of length 1. When
  72. writing an assignment file a whole row of each array is assigned at once
  73. m[3]="9b5fff7f" unless the row is only one element long, in which case each
  74. element is assigned separately. The default behavior of ReadAssignmentLine and
  75. PrintAnAssignment is to use the binary object assignments only for integers
  76. (including char) and to write it only when it would greatly reduce the file
  77. size. The motivation for this extension is to provide a compact way to specify
  78. the contents of an image, typically an array of small integers. It may also be
  79. useful in situations where one wants to save and restore the exact value of a
  80. double, since typical implementations of the C stdio library lose a few bits of
  81. precision translating to or from decimal representations of floating numbers.
  82. You grant or deny permission to read and write hex-encoded binary objects by
  83. setting or clearing two flag bits, assignNoHexInts and assignHexFloats, which
  84. are explained below.
  85.  
  86. DESCRIBING YOUR VARIABLES TO THE ASSIGN ROUTINES
  87.  
  88. The Assign routines use your pre-existing C variables. Each C variable that
  89. you want to be able to load from (or print to) an assignment file must be
  90. described by a "Description" structure, which has fields for the type, name,
  91. address ("ptr"), and other characteristics of your C variable.
  92.     typedef struct {
  93.         short type;
  94.         unsigned sizedOnce:1;    /* Is dim[] meaningful? */
  95.         unsigned sized:1;        /* Is dim[] final? */
  96.         unsigned malloced:1;    /* Allocated by malloc? */
  97.         char *name;
  98.         void *ptr;                /* for array, address of element zero */
  99.         long dim[ASSIGN_DIMS];    /* zero indicates a scalar */
  100.         long firstElement;/* subscript of first element of last dimension. Usually 0 */
  101.         const char *comment;    /* text string, or NULL */
  102.     } Description;
  103. The routines Describe, DescribeArray, and DescribeFirstLast are convenient ways
  104. to set all the fields. Use these routines (instead of explicitly loading the
  105. fields yourself) to enhance the compatibility of your programs with future
  106. enhancements to Assign.c, which might redefine the fields of the Description
  107. structure.
  108.     Description Describe(short type,void *ptr,char *name,const char *comment);
  109.     short n;
  110.     d[i++]=Describe(shortType,&n,"n","hello");
  111. The available types fall into three groups. The basic types correspond to the
  112. basic types in C: charType, unsignedCharType, shortType, unsignedShortType,
  113. longType, unsignedLongType, floatType, shortDoubleType, and doubleType. A
  114. second, corresponding, group of types, adding the word "Ptr", requests dynamic
  115. array allocation: charPtrType, unsignedCharPtrType, shortPtrType,
  116. unsignedShortPtrType, longPtrType, unsignedLongPtrType, floatPtrType,
  117. shortDoublePtrType, and doublePtrType. The third group consists solely of the
  118. "stringType", which is handled somewhat differently from the charPtrType. (Note:
  119. since Standard C doesn't allow the "short double" type, the shortDoubleType and
  120. shortDoublePtrType are conditionally compiled, controlled by SHORT_DOUBLE_OK,
  121. which is defined in VideoToolbox.h.) The name argument string is used in reading the
  122. assignment file. The ptr argument should be the address of a C variable of the
  123. type specified by the type argument (e.g. float). When the type is one of the
  124. Ptr types, or stringType, then the C variable should be a pointer of the
  125. appropriate kind, so the "ptr" argument you supply will be the address of that
  126. pointer. The last argument to Describe() is comment, which must be a string or
  127. NULL. Any call to PrintAnAssignment() will print the comment (if not NULL) after
  128. the assignment statement, surrounding it by /* */.
  129.     Description DescribeArray(short type,void *ptr,char *name,const char *comment,...);
  130.     double b[3][4];
  131.     d[i++]=DescribeArray(doubleType,&b,"b","coefficients",3L,4L,0L);
  132. For the basic and string types, the supplied C variable can be an array, whose
  133. dimensions are specified as additional arguments to DescribeArray. There may
  134. be up to ASSIGN_DIMS dimensions. Each dimension must be a long, and the argument
  135. list must be terminated by 0L, i.e. a zero of type long.
  136.  
  137. Arrays of stringType are allowed, e.g. 
  138.     char *nicknames[10];
  139.     DescribeArray(stringType,&nicknames,"nicknames",NULL,10L,0L);
  140. But, in that case, malloced space for a string is not freed when a new string 
  141. is assigned.
  142.  
  143. READING AN ASSIGNMENT FILE
  144.  
  145. ReadAssignmentLine does all the reading. ReadAssignmentBlock and
  146. ReadAssignmentFile just call ReadAssignmentLine repeatedly. One by one,
  147. ReadAssignmentLine reads assignments from the assignment file (until it reaches
  148. the end of the line, or detects an error). Syntax errors are reported.
  149. ReadAssignmentLine gets a variable name from the assignment file and looks for a
  150. matching name in the user-supplied Description array. Any inconsistency of the
  151. assignment statement with the variable's declared type and dimensions is
  152. reported. Then the assignment is made.
  153.  
  154. Assignment to basic variables is straightforward, equivalent to assignment in
  155. a C program, e.g.
  156.     a[2][1]=3.0;
  157. When ReadAssignmentLine assigns a string to a stringType variable,
  158.     s="hello world";
  159. the string is allocated by malloc() and the string's address is poked into your
  160. char * variable. Prior to assignment of a string, FreeADescribedVar will be
  161. called, which, if any pre-existing string was allocated by malloc--as indicated
  162. by the d->malloced flag--will free it. You can free all your strings (and
  163. PtrType variables) by calling FreeDescribedVars.
  164.  
  165. The PtrType variables initially have no space allocation for storage of data. Each
  166. unallocated Ptr variable is automatically allocated space for a scalar or array
  167. dimensioned just big enough to contain all the assignments in the part (or
  168. "gulp") of the assignment file that the user has just asked to read: a line, a
  169. block, or the whole file. (If the Ptr variable is dimensioned, from a call to
  170. DescribeArray, but not allocated, then it will be allocated at the declared
  171. size.) Once allocated, the array dimensions are fixed, unless the user frees the
  172. allocations by calling FreeDescribedPtrVars() or FreeDescribedVars(), which also
  173. clear the array's dimensions (whether set dynamically or by an initial call to
  174. DescribeArray). Restricting the scan to the current gulp makes it possible to
  175. read assignment files in which the array sizes change from gulp to gulp,
  176. provided only that between gulps the user calls FreeDescribedPtrVars() or
  177. FreeDescribedVars(). An inconsistent number of array dimensions
  178.     a[0]=1; a[0][0]=1;
  179. within a gulp is flagged as an error. 
  180.  
  181. ROUTINES
  182.  
  183.     stream=OpenCalFileWrite(filename);
  184. Open up a calibration file for appending. If the file exists in the current
  185. directory, it is used. If not, then if it exists in the Preferences folder, it
  186. used. If not, the file is created in the Preferences folder.
  187.  
  188.     stream=OpenCalFileRead(filename);
  189. Open up a calibration file for reading. First looks in the current directory,
  190. then in the preferences folder. On success returns the opened file's stream. On
  191. failure returns NULL.
  192.  
  193.     stream=OpenCalFileReadAndCheck(filename);
  194. Open up a calibration file for reading. If the file exists in the current
  195. directory, it is used. If not, then if it exists in the preferences folder, it
  196. used. If no file is found then prints an error message and exits.
  197.  
  198.     AppendDescriptions(&d,s);
  199. Appends the second descriptions array onto the end of the first, which is
  200. reallocated with more space. The source array is not freed; the caller should do
  201. that. Both arrays must be null-terminated.
  202.  
  203.     CopyDescriptions(d,s);
  204. Copy one null-terminated array of descriptions to another, which is assumed to
  205. be big enough.
  206.  
  207.     d=AllocateDescriptions(n);
  208. Allocate space for variable descriptions. Adds one to the passed size to hold
  209. the null descriptor. Nulls the first element.
  210.  
  211.     FreeDescriptions(d);
  212. Free the descriptions array. Doesn't affect the described variables.
  213.  
  214.     n=NumberOfDescriptions(d);
  215. Find the size of an array of descriptions. Does not count the trailing null
  216. description.
  217.  
  218.     d[i]=NullDescription();
  219. Returns a null description, to terminate a descriptions array.
  220.  
  221.     if( IsNullDescription(d[i]) )...;
  222. Determine whether we are looking at a null description. Implemented as a macro.
  223.  
  224. Description Describe(short type,void *ptr,char *name,const char *comment);
  225. Description DescribeArray(short type,void *ptr,char *name,const char *comment,...);
  226.     double a,*p,x[3];
  227.     d[i++]=Describe(doubleType,&a,"a","hello");
  228.     d[i++]=Describe(doublePtrType,&p,"p",NULL);
  229.     d[i++]=DescribeArray(doubleType,&x,"x",NULL,3L,0L);
  230. Describe and DescribeArray merely return a Description with the field values
  231. that you supply. Use them to make your programs more readable, and to enhance
  232. the compatibility of your programs with future enhancements to Assign.c, which
  233. might redefine the fields of the Description structure. DescribeArray() accepts
  234. a variable number of arguments specifying the array dimensions. You may supply
  235. any number of array dimensions (up to ASSIGN_DIMS), but they MUST be long, and
  236. the argument list MUST be terminated by a 0L following the list of dimensions.
  237. Any additional arguments following the 0L are ignored. A PtrType variable may be
  238. described by DescribeArray(), specifying the dimensions of the storage area to
  239. be allocated, or may be described by Describe() in which case the dimensions
  240. (none up to ASSIGN_DIMS) will be determined from the first gulp of the
  241. assignment file. In either case, storage for the PtrType variable is allocated
  242. only when it is encountered in the assignment file. The array dimensions of a
  243. PtrType variable specified when calling DescribeArray() are wiped out if you
  244. later call FreePtrVariables(), with the same result as just calling Describe().
  245.  
  246. TYPES: charType, unsignedCharType, shortType, unsignedShortType, longType,
  247. unsignedLongType, floatType, shortDoubleType, doubleType, charPtrType,
  248. unsignedCharPtrType, shortPtrType, unsignedShortPtrType, longPtrType,
  249. unsignedLongPtrType, floatPtrType, shortDoublePtrType, doublePtrType,
  250. stringType.
  251.  
  252. Description DescribeFirstLast(short type,void *ptr,char *name
  253.     ,const char *comment,long firstElement,long lastElement);
  254.     float *a;
  255.     a=vector(1,10);    /* a Numerical Recipes in C allocation routine */
  256.     d[i++]=DescribeFirstLast(floatType,a,"a",NULL,1L,10L,0L);
  257. This allows you to specify a 1-dimensional array with a nonstandard subscript
  258. range, e.g. starting with subscript 1, as in Numerical Recipes in C. The "ptr"
  259. argument should always point to element zero, even if that element is not part of
  260. the array's allocated storage. 
  261.  
  262.     error=UnequalDescribedVars(descriptions1,descriptions2,flags);
  263.     error=UnequalDescribedVarPair(d1,d2,flags);
  264. These routines compare the data pointed to by the two Description arrays or
  265. structs. They return 0 if the Descriptions are legal and the data are
  266. equal, and a nonzero error code (or PrintfExit, depending on flags) otherwise.
  267. (Comparison of floating numbers allows a tolerance of +/- one part in a million,
  268. because converting to and from decimal may lose some precision, and considers
  269. all NANs equal because NAN indices (NAN04 vs NANFF) are not preserved by most
  270. operations.) This makes it easy to verify what was written to an assignment
  271. file. Just create a new data structure and a Description array describing it,
  272. call ReadAssignmentFile, and use UnequalDescribedVars to verify that you read
  273. back exactly what you wrote.
  274.  
  275.     n=CopyDescribedVars(descriptions1,descriptions2,flags);
  276.     n=CopyADescribedVar(d1,d2,flags);
  277. These routines copy the data pointed to by the first Description array or
  278. struct, overwriting the data pointed to by the second. They return 0 on success,
  279. i.e. if the Descriptions are legal and the data types and names are consistent,
  280. and a nonzero error code (or PrintfExit, depending on flags) otherwise. This
  281. makes it easier to read data into a temporary area, and then, if these are the
  282. data we want, to then copy them into the real variables.
  283.  
  284.     n=InitializeDescribedVars(descriptions,flags);
  285.     n=InitializeADescribedVar(d,flags);
  286. Initialize the described variables. All integer variables
  287. are set to zero, all floating variables are set to NAN, and all the strings are
  288. set to point to a particular empty string "". Any PtrType scalars and arrays
  289. that have already been allocated will be initialized; unallocated PtrType
  290. variables are NULLed.
  291.  
  292.     n=ReadAssignmentLine(stream,descriptions,flags);
  293. Interprets one line from the stream (splicing continuation lines), and continues
  294. to read further lines, if necessary, to reach the end of any incomplete comment
  295. or assignment. ReadAssignmentBlock() and ReadAssignmentFile(), below, do all
  296. their reading by repeatedly calling ReadAssignmentLine().
  297.  
  298.     blank=AssignmentLineWasBlank();
  299. Returns true (i.e. 1) unless the most recent call to ReadAssignmentLine() read
  300. some non-blank text, in which case it returns false (i.e. 0).
  301.  
  302.     n=ReadAssignmentBlock(stream,descriptions,flags);
  303. Interprets lines from the stream until it reads a blank line. (Blank lines within
  304. an assignment or comment /* */ are ignored.) Implemented by repeatedly calling
  305. ReadAssignmentLine() until AssignmentLineWasBlank() is true. 
  306.  
  307.     n=ReadAssignmentFile(filename,descriptions,flags);
  308. Interpret a whole file. Implemented by repeatedly calling ReadAssignmentLine().
  309.  
  310.     FreeDescribedPtrVars(descriptions,flags);
  311. Frees any allocated storage (and wipes out the array dimensions) for any
  312. described PtrType variables; they will be appropriately dimensioned and
  313. allocated when they are next read from an assignment file. This allows reading
  314. of assignment files in which array dimensions may change from gulp to gulp.
  315.  
  316.     FreeDescribedVars(descriptions,flags);
  317. Frees any allocated storage (and wipes out the array dimensions) for any
  318. described PtrType and stringType variables.
  319.  
  320.     FreeADescribedVar(description,flags);
  321. Frees any allocated storage (and wipes out the array dimensions) for a described
  322. variable. This only affects PtrType and stringType variables.
  323.  
  324.     KeepDescribedVars(descriptions,flags);
  325. Prevents the freeing of all the allocated storage for all the described PtrType
  326. and stringType variables. Call this when you want to copy the pointer elsewhere
  327. and you don't want Assign to dispose of the storage pointed to. (This routine
  328. simply clears all the "malloced" fields in the descriptions.)
  329.  
  330.     i=FindDescription(d,ptr,flags);
  331. Finds your C variable's description in the supplied array. Returns the subscript
  332. (≥0) of the matching Description, or, if the search fails, then either PrintfExits
  333. with an error or returns a negative error code, as determined by the setting of
  334. the assignNoPrintfExit bit in flags. Your C variable's dimensions are in the
  335. d[i].dim[] field, which is dimensioned ASSIGN_DIMS.
  336.  
  337.     dim=FindDescribedDim(d,ptr,n,flags);
  338. Calls FindDescription to find your C variable's description and returns the
  339. size of your variable's n-th dimension. (All dimensions after the first
  340. ASSIGN_DIMS return zero.) Handling of search failure as in FindDescription().
  341.  
  342.     n=PrintAnAssignment(stream,d,flags);
  343. Prints out the name and value of the described variable as an assignment
  344. statement "i=2;" suitable for reading by ReadAssignmentLine.
  345.  
  346.     n=PrintAssignments(stream,descriptions,flags);
  347. Calls PrintAnAssignment and fprintf(stream,"\n"); for each described variable.
  348.  
  349.     n=PrintAssignmentsToFile(filename,descriptions,flags);
  350. Opens the file, calls PrintAssignments, and closes the file. If a file of that 
  351. name already exists it appends to the existing file.
  352.  
  353.     n=ReadLuminanceRecord(filename,LP,flags)
  354. This uses ReadAssignmentFile() to interpret a LuminanceRecord?.h file. This
  355. routine is in ReadLuminanceRecord.c.
  356.  
  357. In all cases the returned value, n, is either positive (>=0), indicating the
  358. number of data that were fully processed, or negative, indicating an error code
  359. defined in VideoToolbox.h. Each array element, scalar, or string is considered a
  360. datum. Any assignments that referred to out-of-range array elements or unknown
  361. variables are skipped and are not counted.
  362.  
  363. The first argument is either a filename (c string) or a stream (FILE *)
  364. returned by fopen(). Open the file in text, not binary, mode, so that
  365. '\r' and '\n' characters will be translated properly.
  366.  
  367. The second argument, "descriptions", is an array of Descriptions of
  368. your variables. The number of array elements is not given. Instead you mark the
  369. end by zeroing the "type" field of the last Description. The "Description" data
  370. structure is defined in VideoToolbox.h.
  371.  
  372. The third argument, "flags", allows you to specify various runtime options. Each
  373. option is controlled by a different bit; flags is the sum of the desired
  374. options. Most users will want the default behavior, i.e. flags==0. The default
  375. behavior of PrintAnAssignment is to never hex-encode floats (float and double)
  376. and to only hex encode integers (i.e. char, short, and long, signed or unsigned)
  377. when this would reduce the number of lines in the assignment file (i.e. when
  378. the last dimension exceeds typeSize+2).
  379.  
  380. FLAGS
  381.  
  382. "assignNoPrintfExit" is a flag that asks all the routines to return an error
  383. code if they cannot satisfy the request, otherwise the routines call PrintfExit
  384. with a diagnostic error message that pinpoints the location of the error.
  385.  
  386. "assignReportUnknown" asks ReadAssignmentLine to report an error if an unknown
  387. variable appears in the assignment file. Array elements with out-of-range
  388. subscripts are considered unknown variables. In the absence of this flag,
  389. attempts to assign to unknown variables are silently skipped (the data are
  390. discarded).
  391.  
  392. "assignNoHexInts" tells ReadAssignmentLine and PrintAnAssignment to never read
  393. or save char, short, or long as hex strings. This sacrifices the compactness of
  394. hex strings, but enhances human readability of the assignment file. (It also
  395. preserves compatibility with C, making it possible to #include the assignment
  396. file inside a C program, and preserves portability of the assignment file
  397. between computers that use different byte orderings.)
  398.  
  399. "assignHexFloats" tells PrintAnAssignment to always save floats (float and
  400. double) as hex strings, and tells ReadAssignmentLine to allow hex strings. This
  401. preserves the exact value (unlike decimal representation, which loses a few
  402. least-significant bits in typical implementations of the C stdio library), but
  403. sacrifices human readability and portability of the assignment file since the
  404. binary representation of floats is highly dependent on the compiler options and
  405. the kind of computer. (It also sacrifices compatibility with C, making it
  406. impossible to #include the assignment file.)
  407.  
  408. "assignNoComment" tells PrintAnAssignment not to print the comment field.
  409.  
  410. "assignEchoFile", primarily an aid to debugging, prints each line from the stream
  411. as it is read by ReadAssignmentLine.
  412.  
  413. "assignEchoAssignments", primarily an aid to debugging, calls PrintAnAssignment
  414. after each assignment is performed by ReadAssignmentLine. Uncommented newline
  415. characters in the assignment file are echoed as well. (If assignReportUnknown is
  416. off then assignment statements containing unknown variables or out-of-bounds
  417. array references are echoed as comments: /*UNKNOWN: x=3; */.)
  418.  
  419. "assignEchoComments", primarily an aid to debugging, prints both /*..*/ and
  420. //-style comments as they are read by ReadAssignmentLine. Uncommented newline
  421. characters in the assignment file are echoed as well.
  422.  
  423. ERRORS
  424.  
  425. An error code is returned only if the assignNoPrintfExit flag is set. Otherwise
  426. PrintfExit() is called with a diagnostic message.
  427.  
  428. -1 assignMemoryError: couldn't allocate enough memory.
  429. -2 assignTypeError: unknown type, or array of string, which is not allowed.
  430. -3 assignVariableError: couldn't parse the variable name.
  431. -4 assignUnknownVariableError: unknown variable; can only occur if the 
  432.     assignReportUnknown flag is set.
  433. -5 assignSubscriptError: couldn't parse the subscript.
  434. -6 assignSubscriptBoundsError: out-of-bounds array element; this error is flagged only 
  435.     if the assignReportUnknown flag is set.
  436. -7 assignEqualsError: couldn't find the equals sign.
  437. -8 assignConstantError: couldn't parse the constant.
  438. -9 assignHexError: couldn't parse a hex-encoded binary object constant.
  439. -10 assignSemicolonError: couldn't find the semicolon.
  440. -11 assignFileError: couldn't open the file.
  441. -12 assignInconsistentDescriptionsError: two descriptions are inconsistent.
  442. -13 assignUnequalDataError: two described variables have significantly different data.
  443.  
  444. IMPORTANT: Do not forget to mark the end of your Description array by a Description 
  445. with a type of zero.
  446.  
  447. USING ASSIGN.C
  448.  
  449. It is suggested that those who want to use this package create a header file
  450. with a typedef for a data structure, and write a subroutine that allocates and
  451. fills a Description array describing the data structure's fields. For example,
  452. Luminance.h defines the LuminanceRecord structure and ReadLuminanceRecord.c 
  453. contains the function,
  454.     Description *DescribeLuminanceRecord(LuminanceRecord *LP);
  455. that creates a Description array describing the particular LuminanceRecord structure.
  456.  
  457. CONTROLLING EXPERIMENTS
  458.  
  459. Assign.c was originally written to read parameter files that control
  460. experiments. Typical psychophysical and physiological experiments are very
  461. complicated and require lots of adjustable parameters. One needs an easy way to
  462. change them all that is self documenting and easily reproduced, possibly months
  463. later. The routines provided here come in various flavors allowing you to read a
  464. line at a time (with any number of assignments on the line), a block at a time
  465. (blocks are separated by blank lines), or a whole file at a time. A line may be
  466. continued by ending it with backslash \. In controlling psychophysical
  467. experiments I use a block at the beginning of the file to define the general
  468. experiment followed by a block for each psychophysical "block"; within the block
  469. each line specifies a different experimental condition.
  470.  
  471. If you decide to read the assignment file a bit at a time, bear in mind that
  472. ReadAssignmentLine will immediately return or PrintfExit if the assignment file
  473. contains even a single error. It is strongly suggested that your experimental
  474. program begin by doing a dry run, reading the whole assignment file through to
  475. check for errors, before initializing your variables, and reading it again a bit
  476. at a time as the experiment progresses. It would obviously be very bad to have
  477. the interpreter quit near the end of a 3 hour experiment.
  478.  
  479. READING AND WRITING CALIBRATION DATA
  480.  
  481. David Brainard and I have been discussing how to save and read calibrations of
  482. video displays in a portable way, so that the vision community could share
  483. calibration programs, and experimental programs could simply read in the data
  484. associated with the particular display. The current idea is that there would be
  485. a text file called "Monitor nn calib" associated with each display (where nn is
  486. the video card's slot number), and that this file would hold all kinds of
  487. calibration data for this display, typically produced by a variety of
  488. calibration programs that would each append their results. On a Macintosh
  489. computer these calibration files would reside in the Preferences folder. (Where
  490. should they go on a DOS machine?) David has developed color calibration software
  491. and I've developed software to calibrate gamma and MTF. We are now rewriting
  492. these to make them more portable. We have begun drafting an open-ended standard
  493. for this calibration file, to allow any number of programs to read and write to
  494. it, extracting or adding the data they need and know about and ignoring the
  495. rest. Tentatively, in order to conform to this calibration standard a new
  496. supplement (e.g. to calibrate the geometry of the display) should include: 1. a
  497. C header file that defines a suitable data structure to hold the measurements
  498. (and a few standard facts, e.g. the date of calibration, the name of the video
  499. card and serial number of the monitor, and the names of the person and program
  500. that did the calibration), 2. a C subroutine that accepts a pointer to such a
  501. data structure and returns a pointer to a "Description" array describing each of
  502. the data structure's fields. 3. a program (in any language) that makes the
  503. measurements and appends them to the monitor's calibration file as C assignments
  504. to the data structure's fields, which is easily accomplished by one call to
  505. PrintAssignmentFile. These C assignments must be readable by ReadAssignmentFile
  506. using the Description array created in 2. above, and it is strongly recommended
  507. that the calibration program itself call ReadAssignmentFile, and use
  508. UnequalDescribedVars() to verify that it read back exactly what it wrote. 4.
  509. finally, it will normally be important to provide some sort of advice on how to
  510. use the calibration data when they are read from the calibration file.
  511.  
  512. EXAMPLE
  513.  
  514. An assignment file might contain this:
  515.     /* first block */
  516.     viewingDistance=57.0;
  517.     trials=40;
  518.     message="Monitor calibrated November 21, 1993 by Katie Burns";
  519.     a=3;
  520.     
  521.     // second block
  522.     logC=-1.0;
  523.     a[0]=1;
  524.     
  525.     // third block
  526.     logC=-2; 
  527.     a[1][1]=1.1;a[0][0]=-INF;
  528.  
  529. Here is a sample program to read the assignments given above:
  530. #include "VideoToolbox.h"
  531. #include "assert.h"
  532. typedef struct {
  533.     double *a,logC,viewingDistance;
  534.     long trials;
  535.     char *message;
  536. } Psychophysics;
  537. Description *DescribePsychophysics(Psychophysics *p);
  538.  
  539. Description *DescribePsychophysics(Psychophysics *p)
  540. {
  541.     Description *d;
  542.     int i;
  543.     
  544.     d=AllocateDescriptions(10);
  545.     i=0;
  546.     d[i++]=Describe(stringType,&p->message,"message",NULL);
  547.     d[i++]=Describe(doubleType,&p->viewingDistance,"viewingDistance",NULL);
  548.     d[i++]=Describe(shortType,&p->trials,"trials",NULL);
  549.     d[i++]=Describe(doubleType,&p->logC,"logC",NULL);
  550.     d[i++]=Describe(doublePtrType,&p->a,"a",NULL);
  551.     assert(i<=10);        /*  make sure array was big enough */
  552.     d[i++]=NullDescription();        /*  mark end of array */
  553.     return d;
  554. }
  555.  
  556. void main(void)
  557. {
  558.     Description *d;
  559.     Psychophysics psychophysics,*p;
  560.     short i,flags=0;
  561.     FILE *stream;
  562.     
  563.     p=&psychophysics;
  564.     d=DescribePsychophysics(p);
  565.     InitializeDescribedVars(d,flags);
  566.     stream=fopen("assignments","r");
  567.     do{
  568.         printf("\n/******** New block ********/\n");
  569.         ReadAssignmentBlock(stream,d,flags);
  570.         /*
  571.         a real program would do something useful here with the data in p
  572.         */
  573.         PrintAssignments(stdout,d,flags);
  574.         FreeDescribedPtrVars(d,flags);
  575.     } while(!feof(stream));
  576.     fclose(stream);
  577.     FreeDescriptions(d);
  578. }
  579.  
  580. NOTES FOR FUTURE ENHANCEMENT
  581. The "firstElement" approach supports Numerical Recipes vectors, i.e. 1-d arrays.
  582. For multi-dimensional Numerical Recipes arrays I would also need a
  583. "vectoredArray" flag. Vectored arrays would be fairly easy to add, only
  584. affecting ElementPtr, and allocation and freeing. In the meantime, note that
  585. Numerical Recipes provides a convert_matrix routine that provides vectored
  586. addressing of a normal 2-d c array.
  587.  
  588. ACKNOWLEDGEMENTS
  589. Assign.c was inspired by an idea Beau Watson mentioned to me in the 1980's: a
  590. routine to read free-form parameter values at run time. Discussions with David
  591. Brainard motivated the extensions to support arrays, dynamic allocation, and
  592. unknown variables.
  593.  
  594. #endif
  595.